package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"regexp"
	"sort"
	"time"

	"github.com/fatih/color"
	"github.com/jedib0t/go-pretty/table"
)

type Dict map[string]interface{}

var (
	IP_CHANNEL = make(chan Dict, 10)
	IPRE       = regexp.MustCompile(`(\d{1,3}\.){3}\d{1,3}`)
	VP         = color.New(color.Bold, color.FgGreen).SprintFunc()
	KP         = color.New(color.FgBlue).SprintFunc()
	CacheIPS   = make(map[string]Dict)
	DealdIPS   = make(map[string]bool)
	Last       = ""
	TT         = table.NewWriter()
	NO         = 0
)

func OneIp(ip string) (out Dict, err error) {
	if oo, ok := CacheIPS[ip]; ok {
		IP_CHANNEL <- oo
		return oo, nil
	}
	out = make(Dict)
	req, _ := http.NewRequest("GET", fmt.Sprintf("https://ipapi.co/%s/json", ip), nil)

	resp, err := http.DefaultClient.Do(req)
	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return
	}
	json.Unmarshal([]byte(data), &out)
	delete(out, "country_area")
	delete(out, "in_eu")
	delete(out, "languages")
	delete(out, "country_population")
	delete(out, "utc_offset")
	delete(out, "country_tld")
	delete(out, "region_code")
	delete(out, "latitude")
	delete(out, "longitude")

	delete(out, "currency")
	delete(out, "country_code")
	delete(out, "country_name")
	delete(out, "currency_code")
	delete(out, "currency_name")
	delete(out, "continent_code")
	delete(out, "country_capital")
	delete(out, "country_code_iso3")
	delete(out, "country_calling_code")

	CacheIPS[ip] = out
	IP_CHANNEL <- out
	return
}

func ShowIpInfo() {
	for {
		out := <-IP_CHANNEL

		ColorT([]Dict{out})
		// for k, v := range out {
		// 	if v != nil {
		// 		fmt.Println(KP(k), ":", VP(v))
		// 	}
		// }
	}
}

func ParseBloackBoradIP() {
	tick := time.NewTicker(1 * time.Second)
	getBline := func() (o []string) {
		cmd := exec.Command("bash", "-c", "xclip -selection clipboard -o")
		cmd.Stdin = os.Stdin
		out, err := cmd.Output()
		if err != nil {
			log.Fatal(err)
		}
		for _, b := range IPRE.FindAll(out, -1) {
			o = append(o, string(b))
		}
		return
	}
	go ShowIpInfo()
	for {
		select {
		case <-tick.C:
			for _, ip := range getBline() {
				if _, ok := DealdIPS[ip]; !ok {
					DealdIPS[ip] = true
					go OneIp(ip)
					Last = ip
				}

			}

		}
	}
	return
}

func ColorT(args []Dict) {

	// all := 0

	var headers table.Row
	var keys []string
	for no, arg := range args {
		// var data map[string]interface{}
		// yellow := FGCOLORS[0]
		var values table.Row
		if no == 0 {
			for k := range arg {
				keys = append(keys, k)
			}
			sort.Slice(keys, func(i, j int) bool {
				ll := len(keys[i])
				rl := len(keys[j])
				if ll == rl {
					return byte(keys[i][0]) < byte(keys[j][0])
				} else {
					return ll < rl
				}
			})
			for _, k := range keys {
				headers = append(headers, k)
				values = append(values, fmt.Sprint(arg[k]))
			}
		} else {
			for _, k := range headers {
				values = append(values, fmt.Sprint(arg[k.(string)]))
			}
		}
		if NO == 0 {
			TT.AppendHeader(headers)
			TT.SetOutputMirror(os.Stdout)
			TT.SetStyle(table.StyleLight)
			defer func() {
				NO += 4

			}()
			fmt.Print("\033[2J")
		}
		TT.AppendRow(values)
		// if b, err := json.Marshal(arg); err == nil {

		// if err := json.Unmarshal(b, &data); err == nil {

		// }
		// }

	}
	// t.AppendFooter(table.Row{"Total", all})
	// t.SetStyle(table.StyleLight)
	fmt.Printf("\033[1;0H\r")
	TT.Render()
	NO++
}

func main() {
	ParseBloackBoradIP()
}
